home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2004 April / Gamestar_61_2004-04_dvdb.iso / DVDStar / Editace / hltp.exe / {app} / Source Code / Zoners Half-Life Tools / netvis / NetvisSession.cpp < prev    next >
C/C++ Source or Header  |  2001-04-25  |  9KB  |  318 lines

  1. #include "netvis.h"
  2.  
  3. extern long            g_PortalArrayIndex;
  4.  
  5. extern double   I_FloatTime();
  6.  
  7. //
  8. // Packet
  9. //
  10.  
  11. Packet::Packet(const basePacket* packet)
  12. {
  13.     int size = packet->getSize();
  14.     hlassert(size);
  15.     CHAR* payload = new CHAR[size];
  16.     memcpy(payload, packet, size);
  17.     m_Payload = payload;
  18. }
  19.  
  20. const VIS_PACKET& Packet::data() const
  21. {
  22.     const VIS_PACKET* pReturn = (reinterpret_cast<const VIS_PACKET*>((const CHAR*)m_Payload));
  23.     return *pReturn;
  24. }
  25.  
  26.  
  27. //
  28. // NetvisSocket
  29. //
  30.  
  31. bool NetvisSocket::OnAccept(const InetHostAddress &ia, tpport_t port)
  32. {
  33.     Log("Connection accepted from %s\n", ia.getHostname());
  34.     return true;
  35. }
  36.  
  37. NetvisSocket::NetvisSocket(const InetAddress &ia, tpport_t port)
  38.     : TCPSocket(ia, port)
  39. {
  40. }
  41.  
  42.  
  43.  
  44. //
  45. // NetvisSession
  46. //
  47.  
  48. void NetvisSession::Run()
  49. {
  50.     m_Active = true;
  51.  
  52.     VIS_PACKET inpacket;
  53.  
  54.     while (_zhlt_isCancelled() == false)
  55.     {
  56.         if (m_TCPStream.isPending(SOCKET_PENDING_ERROR, 0))
  57.         {
  58.             goto FatalHandler;
  59.         }
  60.         else if (m_TCPStream.isPending(SOCKET_PENDING_INPUT, 0))
  61.         {
  62.             IfDebug(memset(&inpacket, 0, sizeof(inpacket)));
  63.             if (ReadPacket(inpacket))
  64.             {
  65.                 inpacket.HandleIncomingPacket(&inpacket, this);
  66.             }
  67.             else
  68.             {
  69.                 goto FatalHandler;
  70.             }
  71.         }
  72.         else if (m_PacketsCount)
  73.         {
  74.             m_PacketsLock.EnterMutex();
  75.             for (Packet_i it = m_Packets.begin(); it != m_Packets.end(); it++)
  76.             {
  77.                 const VIS_PACKET& outpacket = it->data();
  78.                 if (!WritePacket(outpacket))
  79.                 {
  80.                     m_Packets.clear();
  81.                     m_PacketsCount = 0;
  82.                     m_PacketsLock.LeaveMutex();
  83.                     goto FatalHandler;
  84.                 }
  85.             }
  86.             m_TCPStream.sync();
  87.             m_Packets.clear();
  88.             m_PacketsCount = 0;
  89.             m_PacketsLock.LeaveMutex();
  90.         }
  91.         else
  92.         {
  93.             Sleep(50);
  94.         }
  95.     }
  96.  
  97.     if (m_PacketsCount)
  98.     {
  99.         // Send any remaining packets first (typically a few IS_DONE_PORTAL's are here the main thread hits the terminate code so fast . . . )
  100.         if (m_PacketsCount)
  101.         {
  102.             m_PacketsLock.EnterMutex();
  103.             for (Packet_i it = m_Packets.begin(); it != m_Packets.end(); it++)
  104.             {
  105.                 const VIS_PACKET& outpacket = it->data();
  106.                 WritePacket(outpacket);
  107.             }
  108.             m_TCPStream.sync();
  109.             m_Packets.clear();
  110.             m_PacketsCount = 0;
  111.             m_PacketsLock.LeaveMutex();
  112.         }
  113.     }
  114.  
  115. FatalHandler:
  116.     m_Active = false;
  117.     GOING_DOWN packet;      // if socket dies, pretend it got the GOING_DOWN message so it cleans up properly
  118.     packet.HandleIncomingPacket(&packet, this);
  119. }
  120.  
  121. NetvisSession::NetvisSession(NetvisSocketServer* parent, TCPSocket &server)
  122.     : m_TCPStream(server, 128*1024)
  123. {
  124.     m_Active = false;
  125.     m_Parent = parent;
  126.     m_SyncIndex = 0;
  127.     m_ClientId = 0;
  128.     m_PortalCount = 0;
  129.  
  130.     m_TCPStream.setCompletion(SOCKET_COMPLETION_IMMEDIATE);
  131. }
  132.  
  133. NetvisSession::NetvisSession(const InetHostAddress &host, tpport_t port)
  134.     : m_TCPStream(host, port, 128*1024)
  135. {
  136.     m_Active = false;
  137.     m_Parent = NULL;
  138.     m_SyncIndex = 0;
  139.     m_ClientId = 0;
  140.     m_PortalCount = 0;
  141.  
  142.     m_TCPStream.setCompletion(SOCKET_COMPLETION_IMMEDIATE);
  143. }
  144.  
  145. void NetvisSession::SendPacket(const basePacket* pPacket) 
  146. {
  147.     if ((g_vismode == VIS_MODE_CLIENT) && (g_visstate == VIS_NO_SERVER))
  148.     {
  149.         while (1)
  150.         {
  151.             Sleep(1000);
  152.         }
  153.     }
  154.  
  155.     Packet packet(pPacket);
  156.  
  157.     m_PacketsLock.EnterMutex();
  158.     m_Packets.push_back(packet);
  159.     m_PacketsCount++;
  160.     m_PacketsLock.LeaveMutex();
  161. }
  162.  
  163. bool NetvisSession::WritePacket(const VIS_PACKET& packet)
  164. {
  165.     const CHAR* payload = reinterpret_cast<const CHAR*>(&packet);
  166.     m_TCPStream.clear();
  167.     m_TCPStream.write(payload, packet.getSize());
  168.     m_TCPStream.flush();
  169.     return m_TCPStream.good();
  170. }
  171.  
  172. bool NetvisSession::ReadPacket(VIS_PACKET& packet)
  173. {
  174.     CHAR* payload = reinterpret_cast<CHAR*>(&packet);
  175.     m_TCPStream.clear();
  176.     m_TCPStream.read(payload, sizeof(basePacket));
  177.  
  178.     if (!m_TCPStream.good())
  179.         return false;
  180.  
  181.     int expectedsize = packet.getPacketSizeByType(packet.getType());
  182.     if ((expectedsize == packet.getSize()) || (expectedsize == VARIABLE_LENGTH_PACKET))
  183.     {
  184.         int remaining = packet.getSize() - myoffsetof(VIS_PACKET, data);
  185.         hlassert(remaining >= 0);
  186.         hlassert(remaining + sizeof(basePacket) <= sizeof(VIS_PACKET));
  187.         if (remaining > 0)
  188.         {
  189.             m_TCPStream.read(packet.data, remaining);
  190.         }
  191.     }
  192.  
  193.     return m_TCPStream.good();
  194. }
  195.  
  196.  
  197. void NetvisSession::DisplayClientStats()
  198. {
  199.     float clientpercent = (float)(g_vislocalportal * 50) / (float)g_visportals;
  200.     float serverpercent = (float)(g_serverindex * 50) / (float)g_visportals;
  201.  
  202.     double currenttime = I_FloatTime();
  203.     double elapsed = currenttime - g_starttime;
  204.  
  205.     int idle_seconds = g_idletime / 1000;
  206.     int work_seconds = (int) elapsed - idle_seconds;
  207.     int total_seconds = (int) elapsed;
  208.  
  209.     Log(
  210.         "==================================================\n"
  211.         "Netvis Client #%d statistics [%-5d portals total]\n"
  212.         "System Progress : [%-5d portals] (%3.2f percent)\n"
  213.         "Client Progress : [%-5d portals] (%3.2f percent)\n"
  214.         "Workload        : [%5d seconds] [%d work] [%5d idle]\n"
  215.         "==================================================\n"
  216.         ,g_clientid, g_visportals * 2
  217.         ,g_serverindex, serverpercent
  218.         ,(int)m_PortalCount, clientpercent
  219.         ,total_seconds, work_seconds, idle_seconds);
  220. }
  221.  
  222. //
  223. // NetvisSocketServer
  224. //
  225.  
  226. void NetvisSocketServer::Run()
  227. {
  228.     while (_zhlt_isCancelled() == false)
  229.     {   
  230.         try
  231.         {
  232.             InetAddress addr;
  233.             NetvisSocket server(addr, m_Port);
  234.         
  235.             while (_zhlt_isCancelled() == false)
  236.             {
  237.                 while (server.isPendingConnection(1000))
  238.                 {
  239.                     NetvisSession* newSession = new NetvisSession(this, server);
  240.                     m_ClientsLock.EnterMutex();
  241.                     m_Clients.push_back(newSession);
  242.                     m_ClientsLock.LeaveMutex();
  243.                     newSession->Start();
  244.                 }
  245.             }
  246.         }
  247.         catch (Socket* socket)
  248.         {
  249. // Workaround for a CommonC++ socket bug on Linux which leaves the socket bound after program termination
  250. #ifdef SYSTEM_POSIX
  251.             if (socket->getErrorNumber() == SOCKET_BINDING_FAILED)
  252.             {
  253.                 Sleep(2000);
  254.                 Log("Socket error %d\n retrying . . .", socket->getErrorNumber());
  255.                 Sleep(8000);
  256.             }
  257.             else
  258.             {
  259.                 Sleep(2000); // Wait just long enough for log() functions to be initialized properly in common/log.c
  260.                 Log("Socket error %d\n", socket->getErrorNumber());
  261.             }
  262. #else
  263.             Sleep(2000); // Wait just long enough for log() functions to be initialized properly in common/log.c
  264.             Error("Socket error %d\n", socket->getErrorNumber());
  265. #endif
  266.         }
  267.     }
  268.  
  269.     DisplayServerStats();       // Final stats
  270.  
  271.     IfDebug(Developer(DEVELOPER_LEVEL_MESSAGE, "NetvisSocketServer: waiting on client threads to finish\n"));
  272.     m_ClientsLock.EnterMutex();
  273.     for (Clients_i it = m_Clients.begin(); it != m_Clients.end(); it++)
  274.     {
  275.         delete (NetvisSession*)(*it);
  276.     }
  277.     m_Clients.clear();
  278.     m_ClientsLock.LeaveMutex();
  279.     IfDebug(Developer(DEVELOPER_LEVEL_MESSAGE, "NetvisSocketServer: done waiting on client threads to finish\n"));
  280. }
  281.  
  282. NetvisSocketServer::NetvisSocketServer(tpport_t port)
  283. {
  284.     m_Port = port;
  285. }
  286.  
  287. void NetvisSocketServer::DisplayClientStats(long clientid, unsigned long portalcount, const char* hostname, bool active)
  288. {
  289.     float percent = (float)(portalcount * 50) / (float)g_visportals;
  290.  
  291.     Log("Client #%-2d Status : [%5u portals] (%3.2f percent) [%s%s]\n", clientid, portalcount, percent, hostname, active ? "" : ":INACTIVE");
  292. }
  293.  
  294. void NetvisSocketServer::DisplayServerStats()
  295. {
  296.     float globalpercent = (float)(g_PortalArrayIndex * 50) / (float)g_visportals;
  297.     float localpercent = (float)(g_vislocalportal * 50) / (float)g_visportals;
  298.  
  299.     Log("\n"
  300.          "==================================================\n"
  301.          "Netvis Server Statistics [%-5d portals total]\n"
  302.          "System Progress   : [%-5d portals] (%3.2f percent)\n"
  303.          "Server Progress   : [%-5d portals] (%3.2f percent)\n"
  304.         ,g_visportals * 2
  305.         ,g_PortalArrayIndex, globalpercent
  306.         ,g_vislocalportal, localpercent);
  307.  
  308.     m_ClientsLock.EnterMutex();
  309.     {    
  310.         for (Clients_i it=m_Clients.begin(); it!=m_Clients.end(); it++)
  311.         {
  312.             DisplayClientStats((*it)->m_ClientId, (*it)->m_PortalCount, (*it)->m_RemoteHostname.c_str(), (*it)->m_Active);
  313.         }
  314.     }
  315.     m_ClientsLock.LeaveMutex();
  316.     Log( "==================================================\n");
  317. }
  318.